package aceim.app.widgets.adapters;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.SortedMap;
import java.util.TreeMap;
import aceim.api.dataentity.Buddy;
import aceim.api.dataentity.FileInfo;
import aceim.api.dataentity.FileMessage;
import aceim.api.dataentity.Message;
import aceim.api.dataentity.MessageAckState;
import aceim.api.dataentity.MultiChatRoom;
import aceim.api.dataentity.ServiceMessage;
import aceim.api.dataentity.TextMessage;
import aceim.api.dataentity.tkv.MessageAttachment;
import aceim.api.dataentity.tkv.MessageAttachment.MessageAttachmentType;
import aceim.api.utils.Logger;
import aceim.app.MainActivity;
import aceim.app.R;
import aceim.app.dataentity.Account;
import aceim.app.themeable.dataentity.ChatMessageItemThemeResource;
import aceim.app.utils.ViewUtils;
import aceim.app.view.page.chat.ChatMessageHolder;
import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.text.Spannable;
import android.text.method.LinkMovementMethod;
import android.text.method.MovementMethod;
import android.text.style.ImageSpan;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.CheckBox;
import android.widget.ListView;
import android.widget.TextView;
import com.androidquery.AQuery;
import com.androidquery.callback.BitmapAjaxCallback;
public class MessagesAdapter extends ArrayAdapter<ChatMessageHolder> {
private static SortedMap<String, Drawable> sSmileys;
private static int sSmileyBound;
private DateFormat mDateFormat;
private DateFormat mTimeFormat;
private boolean mDontDrawSmilies = false;
private Object copyModeStarter = null;
private AQuery mAq = null;
private final Account mAccount;
private final Buddy mBuddy;
private final ChatMessageItemThemeResource messageItemLayout;
private final OnClickListener mCheckForCopyClickListener = new OnClickListener() {
@Override
public void onClick(View v) {
mAq.recycle(v).id(messageItemLayout.getCheckboxId()).checked(true);
}
};
public MessagesAdapter(MainActivity activity, Account account, Buddy buddy, ChatMessageItemThemeResource messageItemLayout) {
super(activity, 0, 0);
this.messageItemLayout = messageItemLayout;
this.mAccount = account;
this.mBuddy = buddy;
init(activity);
}
public MessagesAdapter(MainActivity activity, Account account, Buddy buddy, ChatMessageItemThemeResource messageItemLayout, ChatMessageHolder[] objects) {
super(activity, 0, 0, objects);
this.messageItemLayout = messageItemLayout;
this.mAccount = account;
this.mBuddy = buddy;
init(activity);
}
public MessagesAdapter(MainActivity activity, Account account, Buddy buddy, ChatMessageItemThemeResource messageItemLayout, List<ChatMessageHolder> objects) {
super(activity, 0, 0, objects);
this.messageItemLayout = messageItemLayout;
this.mAccount = account;
this.mBuddy = buddy;
init(activity);
}
private void init(MainActivity activity){
mDateFormat = android.text.format.DateFormat.getLongDateFormat(activity);
mTimeFormat = android.text.format.DateFormat.getTimeFormat(activity);
if (sSmileys == null) {
sSmileys = Collections.synchronizedSortedMap(new TreeMap<String, Drawable>(activity.getSmileysManager().getManagedSmileys()));
for (String smiley: new ArrayList<String>(sSmileys.keySet())) {
if (ViewUtils.isSmileyReadOnly(smiley)) {
Drawable value = sSmileys.remove(smiley);
smiley = ViewUtils.escapeOmittableSmiley(smiley);
sSmileys.put(smiley, value);
}
}
sSmileyBound = (int) (activity.getResources().getDisplayMetrics().density * 10);
}
}
@SuppressWarnings("deprecation")
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = messageItemLayout.getView();
}
if (mAq == null) {
mAq = new AQuery(convertView);
} else {
mAq.recycle(convertView);
}
View v = convertView;
ChatMessageHolder holder = getItem(position);
mAq.id(messageItemLayout.getIconImageViewId()).visibility(copyModeStarter != null ? View.GONE : View.VISIBLE);
String filename;
if (!holder.getMessage().isIncoming()) {
filename = mAccount.getFilename();
} else {
Buddy b = null;
if (mBuddy instanceof MultiChatRoom) {
b = ((MultiChatRoom)mBuddy).findOccupantByUid(holder.getMessage().getContactDetail());
}
if (b == null) {
b = mBuddy;
}
filename = b.getFilename();
}
ViewUtils.fillIcon(messageItemLayout.getIconImageViewId(), mAq, filename, getContext());
mAq.id(messageItemLayout.getSenderTextViewId()).text(holder.getSenderName());
colorSenderName(holder, mAq.getTextView());
mAq.id(messageItemLayout.getMessageStatusImageId()).image(BitmapAjaxCallback.getMemoryCached(getContext(), getImageResourceForAckState(holder.getAckState()))).visibility(copyModeStarter == null ? View.VISIBLE : View.INVISIBLE);
mAq.id(messageItemLayout.getCheckboxId()).visibility(copyModeStarter != null ? View.VISIBLE : View.GONE).checked(copyModeStarter != null && copyModeStarter == v);
if (copyModeStarter == null) {
v.setOnClickListener(null);
} else {
v.setOnClickListener(mCheckForCopyClickListener);
}
if (holder.getMessage().getMessageId() == 0) {
v.setBackgroundDrawable(parent.getContext().getResources().getDrawable(R.color.transparent));
} else {
v.setBackgroundColor(0);
}
mAq.id(messageItemLayout.getTimeTextViewId()).text(getFormattedMessageTime(holder));
setTextAndFormat(getMainActivity(), mAq.id(messageItemLayout.getMessageTextViewId()).getTextView(), holder, mDontDrawSmilies);
if (v.getTag() == null || v.getTag() != holder) {
if (hasAttachments(holder)) {
fillAttachments(mAq, holder);
} else {
mAq.id(messageItemLayout.getAttachmentsListViewId()).gone();
}
}
v.setTag(holder);
return v;
}
private void fillAttachments(AQuery aq, ChatMessageHolder holder) {
ViewGroup attachmentsContainer = (ViewGroup) aq.id(messageItemLayout.getAttachmentsListViewId()).getView();
if (attachmentsContainer == null) {
return;
}
attachmentsContainer.removeAllViews();
aq.visible();
for (MessageAttachment a : ((TextMessage)holder.getMessage()).getAttachments()) {
View attachmentView = constructAttachmentView(aq, a);
attachmentsContainer.addView(attachmentView);
}
}
private View constructAttachmentView(AQuery aq, final MessageAttachment attachment) {
View attachmentView = LayoutInflater.from(getContext()).inflate(R.layout.message_attachment, null);
aq.recycle(attachmentView);
aq.id(R.id.title).text(attachment.getTitle());
aq.id(R.id.source).text(attachment.getSource());
switch (attachment.getType()) {
case AUDIO:
case VIDEO:
aq.id(R.id.source).gone();
aq.id(R.id.picture).gone().image((Drawable)null);
aq.id(R.id.play).visible().clicked(new OnClickListener() {
@Override
public void onClick(View v) {
Intent i = new Intent();
i.setAction(Intent.ACTION_VIEW);
i.setDataAndType(Uri.parse(attachment.getSource()), attachment.getType() == MessageAttachmentType.AUDIO ? "audio/*" : "video/*");
getMainActivity().startActivity(i);
}
});
break;
case PHOTO:
aq.id(R.id.source).gone();
aq.id(R.id.play).gone().clicked(null);
aq.id(R.id.picture).visible().image(attachment.getSource(), true, true, 0, R.drawable.dummy_icon);
break;
default:
aq.id(R.id.source).visible().text(attachment.getSource());
aq.id(R.id.play).gone();
aq.id(R.id.picture).gone();
break;
}
return attachmentView;
}
private boolean hasAttachments(ChatMessageHolder holder) {
return holder.getAttachmentsAdapter() == null
&& holder.getMessage() != null
&& holder.getMessage() instanceof TextMessage
&& ((TextMessage)holder.getMessage()).getAttachments().size() > 0;
}
//color sender label according to message type
//TODO maybe add styling support
private void colorSenderName(ChatMessageHolder holder, TextView sender) {
Message text = holder.getMessage();
if (text instanceof ServiceMessage) {
sender.setTextAppearance(getContext(), R.style.chat_message_sender_color_service);
} else if (text instanceof TextMessage) {
TextMessage txt = (TextMessage) text;
sender.setTextAppearance(getContext(), txt.isIncoming() ? R.style.chat_message_sender_color_received : R.style.chat_message_sender_color_sent);
} else {
sender.setTextAppearance(getContext(), android.R.color.primary_text_light);
}
}
private String getFormattedMessageTime(ChatMessageHolder holder) {
Calendar time = Calendar.getInstance();
time.setTimeInMillis(holder.getMessage().getTime());
Calendar now = Calendar.getInstance();
now.setTimeInMillis(System.currentTimeMillis());
if (now.get(Calendar.DATE) == time.get(Calendar.DATE)
&& now.get(Calendar.MONTH) == time.get(Calendar.MONTH)
&& now.get(Calendar.YEAR) == time.get(Calendar.YEAR)) {
return mTimeFormat.format(time.getTime());
} else {
StringBuilder sb = new StringBuilder();
sb.append(mTimeFormat.format(time.getTime()))
.append(" ")
.append(mDateFormat.format(time.getTime()));
return sb.toString();
}
}
private static final int getImageResourceForAckState(MessageAckState ackState) {
int resId;
if (ackState == null) {
resId = R.drawable.btn_check_off_disable;
} else {
switch (ackState) {
case READ_ACK:
resId = R.drawable.btn_check_on_selected;
break;
case RECIPIENT_ACK:
resId = R.drawable.btn_check_on;
break;
default:
resId = R.drawable.btn_check_on_disable;
break;
}
}
return resId;
}
private static final void setTextAndFormat(MainActivity activity, TextView view, ChatMessageHolder holder, boolean dontDrawSmileys) {
MovementMethod mm = view.getMovementMethod();
if (!(mm instanceof LinkMovementMethod))
{
view.setMovementMethod(LinkMovementMethod.getInstance());
}
String text;
if (holder.getMessage() instanceof FileMessage) {
StringBuilder b = new StringBuilder();
b.append(activity.getString(R.string.buddy_sends_files, holder.getSenderName()));
for (FileInfo i : ((FileMessage)holder.getMessage()).getFiles()) {
b.append("\n");
b.append(activity.getString(R.string.file_transfer_request_format, i.getFilename(), ViewUtils.humanReadableByteCount(i.getSize(), true)));
}
text = b.toString();
} else {
text = holder.getMessage().getText();
}
//A hack for aligning ImageSpans correctly in a case of no text except smileys.
view.setText(text + " ", TextView.BufferType.EDITABLE);
Spannable spannable = view.getEditableText();
if (spannable == null) {
return;
}
ViewUtils.contextIndependentURLSpans(spannable);
if (dontDrawSmileys) {
return;
}
for (String key : sSmileys.keySet()) {
int pos = text.indexOf(key);
if (pos < 0) {
continue;
}
Drawable value = sSmileys.get(key);
int height = (int) (view.getTextSize() + sSmileyBound);
int width = (int) ((value.getIntrinsicWidth() + 0.0f)/value.getIntrinsicHeight() * height);
value.setBounds(0, 0, width, height);
while (pos < text.length()) {
if (pos > -1) {
try {
spannable.setSpan(new ImageSpan(value, ImageSpan.ALIGN_BASELINE), pos, pos + key.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
} catch (Exception e) {
Logger.log(e);
}
pos = text.indexOf(key, pos + key.length());
} else {
break;
}
}
byte[] replace = new byte[key.length()];
Arrays.fill(replace, (byte) '_');
text = text.replace(key, new String(replace));
}
if (holder.getMessage() instanceof ServiceMessage) {
view.setTextAppearance(activity, R.style.chat_message_sender_color_service);
}
}
/**
* @return the mDontDrawSmilies
*/
public boolean isDontDrawSmilies() {
return mDontDrawSmilies;
}
public String grabSelectedText(ListView list) {
StringBuilder sb = new StringBuilder();
for (int i=0; i<list.getChildCount(); i++){
View item = list.getChildAt(i);
CheckBox cb = (CheckBox) item.findViewById(messageItemLayout.getCheckboxId());
if (cb.isChecked() && item.getTag() != null) {
ChatMessageHolder holder = (ChatMessageHolder) item.getTag();
Message m = holder.getMessage();
sb.append(getContext().getString(R.string.copy_mode_format,
holder.getSenderName(),
android.text.format.DateFormat.getTimeFormat(getContext()).format(new Date(m.getTime())),
m.getText()));
sb.append('\n');
//cb.setChecked(false);
}
}
return sb.toString();
}
/**
* @param mDontDrawSmilies the mDontDrawSmilies to set
*/
public void setDontDrawSmilies(boolean mDontDrawSmilies) {
this.mDontDrawSmilies = mDontDrawSmilies;
}
public void setCopyMode(boolean copyMode, View starter) {
if (copyMode) {
if (starter != null) {
copyModeStarter = starter;
} else {
copyModeStarter = new Object();
}
} else {
copyModeStarter = null;
}
notifyDataSetChanged();
}
protected MainActivity getMainActivity() {
return (MainActivity) getContext();
}
}